package org.jeecg.common.job;

import lombok.Getter;
import lombok.Setter;
import org.jeecg.common.job.enums.JobConstants;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Date;

public class SchedulerActive {
    private static Logger LG = LoggerFactory.getLogger(SchedulerActive.class);
    private volatile static Scheduler scheduler = null;
    private String jobId;
    private String cycleTime = null;
    private String jobGroup;
    private String jobName;
    private JobConfig jobConfig;
    private JobKey jobKey;
    private Date updateTime;

    public SchedulerActive(String id, String cycleTime, String beanName, String beanMethod, Integer mode, String nodeName, Date updateTime) {
        this.jobId = id;
        this.cycleTime = cycleTime;

        this.jobConfig = new JobConfig();
        jobConfig.setId("job-" + id);
        jobConfig.setJobId(id);
        jobConfig.setBeanName(beanName);
        jobConfig.setBeanMethod(beanMethod);
        jobConfig.setMode(mode.toString());
        jobConfig.setNodeName(nodeName);
        jobConfig.setLockKey(jobConfig.getId());
        this.jobGroup = "job-group-" + this.jobId + jobConfig.getBeanName() + jobConfig.getBeanMethod();
        this.jobName = "job-name-" + this.jobId + jobConfig.getBeanName() + jobConfig.getBeanMethod();
        this.updateTime = updateTime;
    }

    /**
     * 初始化Scheduler
     *
     * @throws SchedulerException
     */
    public void initScheduler() throws SchedulerException {
        synchronized (this) {
            if (scheduler == null) {
                SchedulerFactory schedulerFactory = new StdSchedulerFactory();
                scheduler = schedulerFactory.getScheduler();
                // TODO 定时任务已启动
                scheduler.start();
            }
        }
    }

    public JobConstants.JobManagerStatus start() {
        try {
            this.initScheduler();

            JobDetailImpl detail = new JobDetailImpl();
            detail.setGroup(jobGroup);
            detail.setName(jobName);
            detail.setJobClass(SchedulerJob.class);

            detail.getJobDataMap().put("jobConfig", jobConfig);
            this.jobKey = detail.getKey();

            CronTriggerImpl cronTrigger = new CronTriggerImpl();
            cronTrigger.setGroup("cron-" + jobGroup);
            cronTrigger.setName("cron-" + jobName);
            cronTrigger.setCronExpression(cycleTime);
            scheduler.scheduleJob(detail, cronTrigger);

            cleanCache();
            LG.info("定时任务已启动[Class: " + this.jobConfig.getBeanName() + "." + this.jobConfig.getBeanMethod() + "; " + cycleTime + "]!");
            return JobConstants.JobManagerStatus.SUCCESS;
        } catch (Exception e) {
            LG.error("定时任务启动失败", e);
        }
        return JobConstants.JobManagerStatus.FAIL;
    }

    public JobConstants.JobManagerStatus stop() {
        try {
            // TODO 定时任务停止
            if (scheduler != null && scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);
            }
            LG.info("定时任务停止成功，[Class: " + this.jobConfig.getBeanName() + "." + this.jobConfig.getBeanMethod() + "; " + cycleTime + "]!");
            return JobConstants.JobManagerStatus.SUCCESS;
        } catch (Exception e) {
            LG.error("定时任务停止失败", e);
        }
        return JobConstants.JobManagerStatus.FAIL;
    }

    /**
     * 停止任务
     */
    public void shutdown() {
        try {
            scheduler.shutdown();
            scheduler = null;
        } catch (Exception e) {
            LG.error("定时任务停止失败", e);
        }
    }

    private void cleanCache() {
        try {
            // TODO 清理缓存
        } catch (Exception e) {
            LG.error("清除定时任务缓存失败", e);
        }
    }

    public String getJobId() {
        return jobId;
    }

    public String getBeanName() {
        return this.jobConfig.getBeanName();
    }

    public String getBeanMethod() {
        return this.jobConfig.getBeanMethod();
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    @Getter
    @Setter
    public static class JobConfig implements Serializable {
        private static final long serialVersionUID = 1L;
        public String id;
        public String jobId;
        public String beanName;
        public String beanMethod;
        public String mode;
        public String lockKeyValue;
        public String nodeName;
        public Long count = 0L;
        public String lockKey;
        public String flagKey;
        public String countKey;
        private boolean isLog = true;

        public void setLockKey(String key) {
            key = this.beanName + ":" + beanMethod;
            this.lockKey = key;
            this.flagKey = key + ":flag";
            this.countKey = key + ":count";
            Long cacheCount = 0L;
            this.count = cacheCount;
        }

        public void setBeanName(String beanName) {
            this.beanName = beanName;
            this.isLog = !"serverMonitor".equals(this.beanName);
        }
    }
}
